﻿using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace LightINI
{
    partial class Ini
    {
        public static class Parser
        {
            /// <summary>
            /// 匹配配置段声明的正则
            /// </summary>
            private readonly static Regex regSection;
            /// <summary>
            /// 匹配配置项的正则
            /// </summary>
            private readonly static Regex regItem;

            static Parser()
            {
                regSection = new Regex($@"^\s*\[(?<name>.+?)\]\s*(?<tailComment>[{COMMENT_CHARS}].+)?$");
                regItem = new Regex($@"^\s*(?<key>[^{COMMENT_CHARS}]+?)=(?<quote>['""])?(?<value>.+?)?(?(quote)\k<quote>|)\s*(?<tailComment>[{COMMENT_CHARS}].+)?$");
            }

            /// <summary>
            /// 处理成INI文件对象
            /// </summary>
            /// <param name="rows"></param>
            /// <returns></returns>
            public static Ini Parse(string[] rows)
            {
                var ini = new Ini();

                if (rows == null || rows.Length == 0)
                {
                    return ini;
                }
                var filerows = rows.Select(row => row.Trim()).ToArray();

                Section section = null;

                var buffer = new List<string>();

                foreach (var row in filerows)
                {
                    // 配置段尚不可用时
                    if (section == null)
                    {
                        // 从文件头开始，还没有发现配置段声明行
                        if (!IsSectionRow(row))
                        {
                            buffer.Add(row);
                        }
                        // 行是配置段
                        else
                        {
                            section = ResolveSection(row);
                            section.HeadRows = buffer.ToArray();
                            buffer.Clear();
                            ini.Sections.Add(section);
                        }

                        continue;
                    }

                    if (IsSectionRow(row))
                    {
                        section.TailRows = buffer.ToArray();
                        buffer.Clear();
                        section = ResolveSection(row);
                        ini.Sections.Add(section);
                        continue;
                    }

                    if (IsItemRow(row))
                    {
                        var item = ResolveItem(row);
                        item.HeadRows = buffer.ToArray();
                        buffer.Clear();
                        section.Set(item);
                        continue;
                    }

                    buffer.Add(row);
                }
                return ini;
            }

            public static bool IsSectionRow(string row)
            {
                return regSection.IsMatch(row);
            }

            public static Section ResolveSection(string row)
            {
                var section = new Section();
                var matches = regSection.Match(row);
                if (!matches.Success)
                {
                    return null;
                }

                section.Name = matches.Groups["name"].Value;
                section.Comment = matches.Groups["tailComment"].Success ? matches.Groups["tailComment"].Value : null;

                return section;
            }

            public static bool IsItemRow(string row)
            {
                return regItem.IsMatch(row);
            }

            public static Item ResolveItem(string row)
            {
                var item = new Item();
                var matches = regItem.Match(row);
                if (!matches.Success)
                {
                    return null;
                }

                item.Key = matches.Groups["key"].Value;
                item.Value = matches.Groups["value"].Value;
                item.Comment = matches.Groups["tailComment"].Success ? matches.Groups["tailComment"].Value : null;

                return item;
            }
        }
    }
}
